#include "RequestBatch.hpp"

#include "../Parameters.hpp"
#include "SignedMessage.hpp"
#include "RequestCore.hpp"
#include "MacSignatureMessage.hpp"
#include "SignedRequestCore.hpp"

using namespace BFT::order::messages;

RequestBatch::RequestBatch(boost::shared_ptr<std::vector<boost::shared_ptr<BFT::messages::RequestCore> > > _entries)
{
	entries = _entries;
	bytes_size = 0;	
}

RequestBatch::RequestBatch(boost::shared_ptr<char> _bytes, int _bytes_size, int _count)
{
	entries.reset( new std::vector<boost::shared_ptr<BFT::messages::RequestCore> > );
	int offset =0;
	int num=0;
	int next_req_start=0;
	uint32_t size;
	uint32_t tag;
	int temp_size;
	boost::shared_ptr<char> temp_bytes;
	while (num < _count) //read all the RequestCore in _byte
	{
		offset = next_req_start;
		//read the tag
		tag = ntohs( *(uint16_t*)(_bytes.get()+offset) );
		offset += TAG_SIZE;
//		fprintf(stderr,"tag :%d\n",tag);

		//read the size
		size = ntohl( *(uint32_t*)(_bytes.get()+offset) );
		offset += SIZE_SIZE;
//		fprintf(stderr,"size :%d\n",size);
		
		if (tag == SIGNED_REQUEST_CORE)
		{
			temp_size = size + 
				   BFT::messages::SignedMessage::computeAuthenticationSize() + 
				   BFT::messages::VerifiedMessageBase::getOffset(); 
//			fprintf(stderr,"temp_size :%d",temp_size);
		}
		else
		{
			temp_size = size +
				   BFT::messages::MacSignatureMessage::computeAuthenticationSize(
				   	BFT::Parameters::getFilterCount(), BFT::Parameters::getOrderCount() ) +
				   BFT::messages::VerifiedMessageBase::getOffset();	
		}
		
		temp_bytes.reset( (char*)malloc(temp_size), free);
		memcpy( (void*)temp_bytes.get() , (const void*)(_bytes.get()+next_req_start) , temp_size);
		next_req_start += temp_size;
		
		if(tag == SIGNED_REQUEST_CORE)
			entries.get()->push_back( boost::shared_ptr<BFT::messages::RequestCore>(
				new BFT::messages::SignedRequestCore(temp_bytes, temp_size)));
		/*
		//TODO
		else
			entries.get()->push_back( boost::shared_ptr<RequestCore>(new BFT::messages::FilteredRequestCore(temp_bytes, temp_size)));
		*/
		num++;
	}
	
	if (_bytes_size != next_req_start)
	{
		fprintf(stderr,"error in creating requestbatch, bytes_size: %d, offset: %d \n",_bytes_size,offset);
		exit(93);
	}
	
	bytes = _bytes;
	bytes_size = _bytes_size;
	
}

boost::shared_ptr<char> RequestBatch::getBytes()
{
	if (bytes_size != 0)
		return bytes;
		
// 	std::cerr << entries->size() << std::endl;
// 	std::cerr << entries->at(0).get() << std::endl;
// 	std::cerr << entries->at(0)->getEntry().get() << std::endl;
	for (unsigned int i=0; i<entries.get()->size(); i++) {
	  assert(entries->at(i).get() != NULL);
	  bytes_size += entries->at(i)->getTotalSize();
	}
	
	bytes.reset((char*)malloc(bytes_size), free);
		
	int offset = 0;	
	int entry_size = 0;
	boost::shared_ptr<char> temp_bytes;	
	for (unsigned int i=0; i<entries.get()->size(); i++)
	{	
		temp_bytes = entries.get()->at(i).get()->getBytes(entry_size);
		memcpy( (void*)(bytes.get()+offset) , (const void*)(temp_bytes.get()), entry_size);
		offset += entry_size;
	}
	
	if (offset != bytes_size)
	{
		fprintf(stderr,"something wrong happened while getting bytes from a RequestBatch\n");
		exit(94);
	}
	
	return bytes;	
}

boost::shared_ptr<char> RequestBatch::getBytes(int& _size)
{
	if (bytes_size ==0)
		getBytes();
	
	_size = bytes_size;
	return bytes;
}

int RequestBatch::getSize()
{
	if (bytes_size ==0)
		getBytes();
	
	return bytes_size;
}

bool RequestBatch::equals(boost::shared_ptr<RequestBatch> _rb)
{
	boost::shared_ptr<std::vector<boost::shared_ptr<BFT::messages::RequestCore> > > other_entries = _rb.get()->getEntries();
	bool equal = entries.get()->size() == other_entries.get()->size();
	
	for(unsigned int i=0; i<entries.get()->size() && equal; i++)
		equal = entries.get()->at(i).get()->equals(other_entries.get()->at(i));
	
	return equal;
}

void RequestBatch::printInfo()
{
	fprintf(stdout, "Request batch information:\n");
	fprintf(stdout, "printing %d entries\n", (int)entries.get()->size());
	for(unsigned int i = 0; i< entries.get()->size(); i++)
		entries.get()->at(i).get()->printInfo();
}
